from ctypes import *

class position(Structure):
    _fields_ = [("x", c_int),
                ("y", c_int)]

class coordinates(Structure):
    _fields_ = [("lat", c_double),
                ("lon", c_double)]

class xy_coordinates(Structure):
    _fields_ = [("easting", c_double),
                ("northing", c_double),
                ("zone", c_char_p)]

class Map(Structure):
    _fields_ = [("datum_id", c_char_p),
                ("projection_setup_id", c_char_p),
                ("mmpxy", POINTER(position)),
                ("mmpll", POINTER(coordinates)),
                ("num_points", c_int),
                ("width", c_int),
                ("height", c_int)]
    
    def __init__(self):
        self.positions = []
        self.coordinates = []
    def setDatum(self, datum):
        self.datum_id = datum
    def setProjection(self, projection):
        self.projection_setup_id = projection
    def setWidth(self, width):
        self.width = width
    def setHeight(self, height):
        self.height = height
    def setNumPoints(self, numPoints):
        self.num_points = numPoints
    def addCalibrationPoint(self, lat, lon, x, y):
        self.positions.append(position(x, y))
        self.coordinates.append(coordinates(lat, lon))
    def addCalibrationPoint1(self, lon, lat, x, y):
        self.positions.append(position(x, y))
        self.coordinates.append(coordinates(lat, lon))
    def getCalibrationMap(self):        
        self.num_points = len(self.coordinates)
        coords = coordinates * len(self.coordinates)    
        self.mmpll = coords(*self.coordinates)        
        pos = position * len(self.coordinates)
        self.mmpxy = pos(*self.positions)      
        
class Calibration():
    def __init__(self):
        self._reset = cdll.tbgeo.tbgeo_reset
        self._reset.restype = None
        self._version = cdll.tbgeo.tbgeo_version
        self._version.restype = c_char_p
        self._register = cdll.tbgeo.tbgeo_register_calibration
        self._register.restype = c_bool
        self._register.argtypes = [POINTER(Map)]
        self._toLocal = cdll.tbgeo.tbgeo_to_local    
        self._toLocal.restype = POINTER(coordinates)
        self._getPosition = cdll.tbgeo.tbgeo_get_position
        self._getPosition.restype = POINTER(position)
        self._getPosition.argtypes = [POINTER(Map), POINTER(coordinates)]
        self._getCoordinates = cdll.tbgeo.tbgeo_get_coordinates
        self._getCoordinates.restype = POINTER(coordinates)
        self._getCoordinates.argtypes = [POINTER(Map), POINTER(position)]
        self._error = cdll.tbgeo.tbgeo_last_error
        self._error.restype = c_char_p        
        self._defineProjection = cdll.tbgeo.tbgeo_define_projection
        self._defineProjection.restype = None
        self._defineProjection.argtypes = [c_char_p, c_char_p, c_double, c_double,
                                           c_double, c_double, c_double, c_double,
                                           c_double, c_short, c_char]
        
        self._defineDatum = cdll.tbgeo.tbgeo_define_datum
        self._defineDatum.restype = None
        self._defineDatum.argtypes = [c_char_p, c_char_p, c_double, c_double, c_double]
        import datums
        self._reset()
        for d in datums.datums:
            self._defineDatum(*d)        
        
    def register(self, map):
        map.getCalibrationMap()
        self._defineProjection("x", map.projection_setup_id, 0, 0, 0, 0, 1, 0, 0, -1, 'Z')
        map.setProjection("x")
        self.map = map
        return self._register(self.map)
    def getPosition(self, coords):
        return self._getPosition(self.map, pointer(coords)).contents     
    def getCoordinates(self, pos):
        return self._getCoordinates(self.map, pointer(pos)).contents
    def getError(self):
        return self._error()
